﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using DG.Tweening;
///
/// 无限循环List
///
public class UnlimitedLoopList : UIBase
{
    enum Direction
    {
        Horizontal,
        Vertical
    }
    [SerializeField]
    private RectTransform m_Cell;
    /// <summary>
    /// 一个界面要放的Item的数量    行   列
    /// </summary>
    [SerializeField]
    private Vector2 m_OnePageItemCount;
    [SerializeField]
    Direction direction = Direction.Horizontal;
    [SerializeField, Range(4, 10)]
    private int m_BufferNo;
    private List<RectTransform> m_InstantiateItems = new List<RectTransform>();
    private IList m_Datas;
    /// <summary>
    /// 单个格子的大小，;获取设置值m_Cell.sizeDelta或者预设值Vector2(360, 100)
    /// </summary>
    public Vector2 CellRect
    {
        get
        {
            return m_Cell != null ? m_Cell.sizeDelta : new Vector2(360, 100);
        }
    }
    /// <summary>
    /// 用来计算下拉或者横拉格子的移动，获取单个格子的长度，或者宽度，根据ScrollRect的滑动方向
    /// </summary>
    public float CellScale
    {
        get
        {
            return direction == Direction.Horizontal ? CellRect.x : CellRect.y;
        }
    }
    private float m_PrevPos = 0;
    /// <summary>
    /// 横向 content.anchoredPosition.x     纵向 content.anchoredPosition.y
    /// </summary>
    public float DirectionPos
    {
        get
        {
            return direction == Direction.Horizontal ? m_Rect.anchoredPosition.x : m_Rect.anchoredPosition.y;
        }
    }
    /// <summary>
    /// 页面的第一行(列)在整个conten中的位置
    /// </summary>
    private int m_CurrentIndex;
    private Vector2 m_InstantiateSize = Vector2.zero;
    public Vector2 InstantiateSize
    {
        get
        {
            if (m_InstantiateSize == Vector2.zero)
            {
                float rows, cols;
                if (direction == Direction.Horizontal)
                {
                    rows = m_OnePageItemCount.x;
                    cols = m_OnePageItemCount.y + (float)m_BufferNo;
                }
                else
                {
                    rows = m_OnePageItemCount.x + (float)m_BufferNo;
                    cols = m_OnePageItemCount.y;
                }
                m_InstantiateSize = new Vector2(rows, cols);
            }
            return m_InstantiateSize;
        }
    }
    public int PageCount { get { return (int)m_OnePageItemCount.x * (int)m_OnePageItemCount.y; } }
    /// <summary>
    /// 横向 一行放置几个Item，纵向  一列放置几个Item
    /// </summary>
    public int PageScale
    {
        get
        {
            return direction == Direction.Horizontal ? (int)m_OnePageItemCount.x : (int)m_OnePageItemCount.y;
        }
    }
    /// <summary>
    /// 要拖动的滑动条
    /// </summary>
    private ScrollRect m_ScrollRect;
    /// <summary>
    /// content
    /// </summary>
    private RectTransform m_Rect;
    /// <summary>
    /// 要生成的Item的数量，横向数量*横向数量
    /// </summary>
    public int InstantiateCount
    {
        get
        {
            return (int)InstantiateSize.x * (int)InstantiateSize.y;
        }
    }
    protected void Awake()
    {
        m_ScrollRect = GetComponentInParent<ScrollRect>();
        m_ScrollRect.horizontal = direction == Direction.Horizontal;
        m_ScrollRect.vertical = direction == Direction.Vertical;
        m_Rect = GetComponent<RectTransform>();
        m_Cell.gameObject.SetActive(false);
    }
    /// <summary>
    /// 传进来一个List初始化Content的大小以及生成初始化的Item
    /// </summary>
    /// <param name="data"></param>
    public void Init(object data)
    {
        m_Datas = data as IList;
        if (m_Datas.Count > PageCount)
        {
            setBound(getRectByNum(m_Datas.Count));
        }
        else
        {
            setBound(m_OnePageItemCount);
        }
        if (m_Datas.Count > InstantiateCount)
        {
            while (m_InstantiateItems.Count < InstantiateCount)
            {
                createItem(m_InstantiateItems.Count);
            }
        }
        else
        {
            while (m_InstantiateItems.Count > m_Datas.Count)
            {
                removeItem(m_InstantiateItems.Count - 1);
            }
            while (m_InstantiateItems.Count < m_Datas.Count)
            {
                createItem(m_InstantiateItems.Count);
            }
        }
    }
    /// <summary>
    /// 生成Item：0-count
    /// </summary>
    /// <param name="index"></param>
    private void createItem(int index)
    {
        RectTransform item = GameObject.Instantiate(m_Cell);
        item.SetParent(transform, false);
        item.anchorMax = Vector2.up;
        item.anchorMin = Vector2.up;
        item.pivot = Vector2.up;
        item.name = "item" + index;
        item.anchoredPosition = direction == Direction.Horizontal ?
            new Vector2(Mathf.Floor(index / InstantiateSize.x) * CellRect.x, -(index % InstantiateSize.x) * CellRect.y) :
            new Vector2((index % InstantiateSize.y) * CellRect.x, -Mathf.Floor(index / InstantiateSize.y) * CellRect.y);
        m_InstantiateItems.Add(item);
        item.gameObject.SetActive(true);
        updateItem(index, item.gameObject);
    }
    /// <summary>
    /// 当要生成的Item的数量小于一个页面显示的数量时，移除多余的
    /// </summary>
    /// <param name="index"></param>
    private void removeItem(int index)
    {
        RectTransform item = m_InstantiateItems[index];
        m_InstantiateItems.Remove(item);
        RectTransform.Destroy(item.gameObject);
    }
    ///
    /// 由格子数量获取多少行多少列
    ///
    /// 格子个数
    ///
    private Vector2 getRectByNum(int num)
    {
        return direction == Direction.Horizontal ? new Vector2(m_OnePageItemCount.x, Mathf.CeilToInt(num / m_OnePageItemCount.x)) : new Vector2(Mathf.CeilToInt(num / m_OnePageItemCount.y), m_OnePageItemCount.y);
    }
    ///
    /// 设置content的大小
    ///
    ///行数
    ///列数
    private void setBound(Vector2 bound)
    {
        switch (direction)
        {
            case Direction.Horizontal:
                m_Rect.sizeDelta = new Vector2(bound.y * CellRect.x, 0);
                break;
            case Direction.Vertical:
                m_Rect.sizeDelta = new Vector2(0, bound.x * CellRect.y);
                break;
            default:
                break;
        }
    }
    public float MaxPrevPos
    {
        get
        {
            float result;
            Vector2 max = getRectByNum(m_Datas.Count);
            if (direction == Direction.Horizontal)
            {
                result = max.y - m_OnePageItemCount.y;
            }
            else
            {
                result = max.x - m_OnePageItemCount.x;
            }
            return result * CellScale;
        }
    }
    /// <summary>
    /// 横向移动1   纵向移动-1
    /// </summary>
    public float scale
    {
        get
        {
            return direction == Direction.Horizontal ? 1f : -1f;
        }
    }

    private void Update()
    {
        while (scale * DirectionPos - m_PrevPos < -CellScale * 2)
        {
            if (m_PrevPos <= -MaxPrevPos) return;
            m_PrevPos -= CellScale;
            List<RectTransform> range = m_InstantiateItems.GetRange(0, PageScale);
            m_InstantiateItems.RemoveRange(0, PageScale);
            m_InstantiateItems.AddRange(range);
            for (int i = 0; i < range.Count; i++)
            {
                moveItemToIndex(m_CurrentIndex * PageScale + m_InstantiateItems.Count + i, range[i]);
            }
            m_CurrentIndex++;
        }
        while (scale * DirectionPos - m_PrevPos > -CellScale)
        {
            if (Mathf.RoundToInt(m_PrevPos) >= 0) return;
            m_PrevPos += CellScale;
            m_CurrentIndex--;
            if (m_CurrentIndex < 0) return;
            List<RectTransform> range = m_InstantiateItems.GetRange(m_InstantiateItems.Count - PageScale, PageScale);
            m_InstantiateItems.RemoveRange(m_InstantiateItems.Count - PageScale, PageScale);
            m_InstantiateItems.InsertRange(0, range);
            for (int i = 0; i < range.Count; i++)
            {
                moveItemToIndex(m_CurrentIndex * PageScale + i, range[i]);
            }
        }
    }
    private void moveItemToIndex(int index, RectTransform item)
    {
        item.anchoredPosition = getPosByIndex(index);
        updateItem(index, item.gameObject);
    }
    /// <summary>
    /// 根据index获取Item在content中的位置
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    private Vector2 getPosByIndex(int index)
    {
        float x, y;
        if (direction == Direction.Horizontal)
        {
            x = index % m_OnePageItemCount.x;
            y = Mathf.FloorToInt(index / m_OnePageItemCount.x);
        }
        else
        {
            x = Mathf.FloorToInt(index / m_OnePageItemCount.y);
            y = index % m_OnePageItemCount.y;
        }
        return new Vector2(y * CellRect.x, -x * CellRect.y);
    }
    /// <summary>
    /// 刷新Item上的信息
    /// </summary>
    /// <param name="index"></param>
    /// <param name="item"></param>
    private void updateItem(int index, GameObject item)
    {
        item.SetActive(index < m_Datas.Count);
        if (item.activeSelf)
        {
            //调用外部或者自身的刷新信息的方法
            UpdateItemInfo(index, item);
        }
    }
    [SerializeField]
    string moveSpeedTips = "建议7000-10000";
    [SerializeField]
    float moveSpeed = 10000;//建议7000-10000
    public void Move_m_Rect_ToTopAndRefreshItem()
    {
        if (m_Rect.transform.localPosition.y != 0)
        {
            float moveTime = m_Rect.transform.localPosition.y / moveSpeed;
            Tweener tweener = m_Rect.transform.DOLocalMoveY(0, moveTime).OnComplete(() => { StartCoroutine(MoveItem()); });
        }
        else
        {
            StartCoroutine(MoveItem());
        }
    }
    IEnumerator MoveItem()
    {
        foreach (var item in toggles)
        {
            item.interactable = false;
        }
        m_ScrollRect.enabled = false;
        int count = m_InstantiateItems.Count;
        if (count > PageCount)
            count = PageCount;
        for (int i = 0; i < count; i++)//
        {
            updateItem(i, m_InstantiateItems[i].gameObject);
            m_InstantiateItems[i].GetComponent<RectTransform>().localPosition += new Vector3(m_Cell.sizeDelta.x, 0, 0);
        }
        yield return null;
        for (int i = 0; i < count; i++)
        {
            Tweener tr = m_InstantiateItems[i].transform.DOLocalMoveX(0, 0.02f);
            yield return new WaitForSeconds(0.02f);
        }
        m_ScrollRect.enabled = true;
        foreach (var item in toggles)
        {
            item.interactable = true;
        }
    }
}